/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.uhk.ppro.response.service;

import cz.uhk.ppro.response.form.StudentsCourses;
import cz.uhk.ppro.response.model.Answer;
import cz.uhk.ppro.response.model.Course;
import cz.uhk.ppro.response.model.Question;
import cz.uhk.ppro.response.model.Student;
import cz.uhk.ppro.response.model.Teacher;
import cz.uhk.ppro.response.model.Test;
import cz.uhk.ppro.response.model.Types;
import cz.uhk.ppro.response.form.TestsCourses;
import cz.uhk.ppro.response.model.MobileTests;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author Filip Valenta
 */
@Repository
@Transactional
public class DatabaseServiceImpl implements DatabaseService {

    @PersistenceContext
    private EntityManager em;


    @Override
    @Transactional(readOnly = true)
    public List<Student> getStudenti()
    {
        return this.em.createQuery("from Student").getResultList();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Student> getStudentiByLastName()
    {
        return this.em.createQuery("from Student order by lastName").getResultList();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Question> getQuestions(Test t)
    {
        return this.em.createQuery("from Question q where q.test.id = " + String.valueOf(t.getId())).getResultList();
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<Question> getQuestionsByIdTest(int id){
        
       return this.em.createQuery("from Question q where q.test.id = " + String.valueOf(id)).getResultList(); 
    }

    @Override
    @Transactional(readOnly = true)
    public List<Answer> getAnswers(Question q)
    {
        return this.em.createQuery("from Answer a where a.question.id = " + String.valueOf(q.getId())).getResultList();
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<Answer> getAnswersByQuestionId(int id)
    {
        return this.em.createQuery("from Answer a where a.question.id = " + String.valueOf(id)).getResultList(); 
    }
      

    @Override
    @Transactional(readOnly = true)
    public List<Course> getKurzy()
    {
        return this.em.createQuery("from Course c where c.teacher.id = :teacher_id")
                .setParameter("teacher_id", this.getLoggedTeacher().getId())
                .getResultList();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Test> getTestsList()
    {
        return this.em.createQuery("from Test").getResultList();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Student> getStudentsList()
    {
        return this.em.createQuery("from Student").getResultList();
    }



    @Override
    @Transactional(readOnly = true)
    public List<Teacher> getTeachers()
    {
        return this.em.createQuery("SELECT teacher FROM Teacher teacher ORDER BY teacher.lastName").getResultList();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Types> getTypes()
    {
        return this.em.createQuery("SELECT types FROM Types types ORDER BY types.name").getResultList();
    }


    @Override
    @Transactional(readOnly = false)
    public void pridejStudenta(Student s) {
        em.persist(s);
        em.flush();
    }

    @Override
    @Transactional(readOnly = false)
    public void pridejKurz(Course c) {
        em.persist(c);
        em.flush();
    }

    @Override
    @Transactional(readOnly = false)
    public void pridej(Test t) {
        em.persist(t);
        em.flush();
    }

    @Override
    @Transactional(readOnly = false)
    public void pridej(Question q) {
        em.persist(q);
        em.flush();
    }

    @Override
    @Transactional(readOnly = false)
    public void pridej(Answer a) {
        em.persist(a);
        em.flush();
    }

    @Override
    public void odstranKurz(int id) {
        Course i = this.getCourseById(id);
        this.em.remove(i);
    }

    @Override
    public void odstranStudenta(int id) {
        Student s = this.getStudentById(id);
        List<Course> courses = s.getCourses();
        for(Course c: courses) {
            c.getStudents().remove(s);
        }
        this.em.remove(s);
    }

    @Override
    public void odstranTest(int id) {
        Test t = this.getTestById(id);
        List<Course> courses = t.getCourses();
        for(Course c: courses) {
            c.getTests().remove(t);
        }
        this.em.remove(t);
    }

    @Override
    public void odstranOtazku(int id) {
        Question q = this.getQuestionById(id);
        this.em.remove(q);
    }

    @Override
    public void odstranOdpoved(int id) {
        Answer a = this.getAnswerById(id);
        this.em.remove(a);
    }

    @Override
    public void upravStudenta(Student s) {


        Student merged = this.em.merge(s);
        this.em.flush();
        s.setId(merged.getId());
    }

    @Override
    public void upravKurz(Course c) {

        c.setTests(this.getTestsConnectedByCourse(c));
        c.setStudents(this.getStudentsConnectedByCourse(c));
        Course merged = this.em.merge(c);
        this.em.flush();
        c.setId(merged.getId());
    }

    @Override
    public void upravTest(Test t) {

        Test merged = this.em.merge(t);
        this.em.flush();
        t.setId(merged.getId());
    }

    @Override
    public void upravOtazku(Question q) {

        Question merged = this.em.merge(q);
        this.em.flush();
        q.setId(merged.getId());
    }

    @Override
    public void upravOdpoved(Answer a) {

        Answer merged = this.em.merge(a);
        this.em.flush();
        a.setId(merged.getId());
    }

    @Override
    @Transactional(readOnly=true)
    public Student getStudentById(int id) {
        return this.em.find(Student.class, id);
    }

    @Override
    @Transactional(readOnly=true)
    public Course getCourseById(int id) {
        return this.em.find(Course.class, id);
    }

    @Override
    @Transactional(readOnly=true)
    public Test getTestById(int id) {
        return this.em.find(Test.class, id);
    }

    @Override
    @Transactional(readOnly=true)
    public Question getQuestionById(int id) {
        return this.em.find(Question.class, id);
    }

    @Override
    @Transactional(readOnly=true)
    public Answer getAnswerById(int id) {
        return this.em.find(Answer.class, id);
    }

    @Override
    public void formUlozOtazkyOpdovedi(Test t){
         for(Question q : t.getQuestions()) {
            q.setTest(t);
            this.pridej(q);
            for(Answer a : q.getAnswers()) {
                a.setQuestion(q);
                this.pridej(a);
            }
        }
    }

    @Override
    public void formEditOtazkyOpdovedi(Test t){
        for(Question q : t.getQuestions()) {
            q.setTest(t);
            this.upravOtazku(q);
            for(Answer a : q.getAnswers()) {
                a.setQuestion(q);
                this.upravOdpoved(a);
            }
        }
    }

    @Override
    public void prolinkujKurzyTesty(TestsCourses tc)
    {
        // TODO: zde by se mozna melo vse predtim promazat
        Course c = this.getCourseById(tc.getCourse_id());
        c.setTests(new ArrayList<Test>());

        for(int id_tests : tc.getTests()) {
            c.getTests().add(this.getTestById(id_tests));
        }
        this.upravKurz(c);
    }

    @Override
    public List<Integer> getTestsIdsConnectedByCourses(Course c)
    {
        List<Integer> ids = new ArrayList<Integer>();
        List<Test> tests = this.getTestsConnectedByCourse(c);
        for(Test t : tests)
        {
            ids.add(t.getId());
        }
        return ids;
    }

    @Override
    public List<Test> getTestsConnectedByCourse(Course c)
    {
        return this.em.createQuery("select t from Test t join t.courses c where c.id = " + String.valueOf(c.getId())).getResultList();
    }

    @Override
    public void prolinkujKurzyStudenty(StudentsCourses sc)
    {
        Course c = this.getCourseById(sc.getCourse_id());
        c.setStudents(new ArrayList<Student>());

        for(int id_students : sc.getStudents()) {
            c.getStudents().add(this.getStudentById(id_students));
        }
        this.upravKurz(c);
    }

    @Override
    public List<Integer> getStudentsIdsConnectedByCourses(Course c)
    {
        List<Integer> ids = new ArrayList<Integer>();
        List<Student> students = this.getStudentsConnectedByCourse(c);
        for(Student s : students)
        {
            ids.add(s.getId());
        }
        return ids;
    }

    @Override
    public List<Student> getStudentsConnectedByCourse(Course c)
    {
        return this.em.createQuery("select s from Student s join s.courses c where c.id = " + String.valueOf(c.getId())).getResultList();
    }

    @Override
    public List<Course> getCoursesAndStudents(Course c, Student s)
    {
        return this.em.createQuery("select c from Course c join c.students s where s.id = :id_student and c.id = :id_course")
                .setParameter("id_student", s.getId())
                .setParameter("id_course", c.getId())
                .getResultList();
    }

    @Override
    public List<Course> getCoursesAndTests(Course c, Test t)
    {
        return this.em.createQuery("select c from Course c join c.tests t where t = :test and c = :course")
                .setParameter("course", c)
                .setParameter("test", t)
                .getResultList();
    }


    @Override
    public Teacher getLoggedTeacher()
    {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return (Teacher) this.em.createQuery("from Teacher t where t.username = :username").setParameter("username", auth.getName()).getSingleResult();
    }

    @Override
    public int getTestByCourseCount(Course c)
    {
        return this.em.createQuery("select t from Test t join t.courses c where c = :course")
                .setParameter("course", c)
                .getResultList().size();
    }
    
    //Metody pro andoid------------------------------
    @Override
    @Transactional(readOnly=true)
    public List<Student> getStudentByUserAndPassword(String user, String password) {
         return this.em.createQuery("select s from Student s where s.user = :user and s.password = :password")
                 .setParameter("user", user)
                 .setParameter("password", password)
                 .getResultList();
    }
    
    @Override
    @Transactional(readOnly=true)
    public List<Test> getTestsByUserId(int id){
        
        return this.em.createQuery(""
                + "select t "
                + "from Student s "
                + "join s.courses c "
                + "join c.tests t "
                + "where s.id = :student").setParameter("student", id).getResultList();

    }
    
    
  


}
